$(function() {
    
    // not_equal
    jQuery.validator.addMethod("not_equal", function(value, element, params) {
        return this.optional(element) || value !== $('[name=' + params[0] + ']').val();
    }, "This field should not be the same as {0} field");
    
    // exact_length
    jQuery.validator.addMethod("exact_length", function(value, element, params) {
        return this.optional(element) || parseInt(value.length) === parseInt(params[0]) ? true : false;
    }, "Please enter {0} characters");
    
    // greater_than
    jQuery.validator.addMethod("greater_than", function(value, element, params) {
        return this.optional(element) || parseInt(value) > parseInt(params[0]) ? true : false;
    }, "Please enter a value greater than {0}");
    
    // less_than
    jQuery.validator.addMethod("less_than", function(value, element, params) {
        return this.optional(element) || parseInt(value) < parseInt(params[0]) ? true : false;
    }, "Please enter a value less than {0}");
    
    // alpha
    jQuery.validator.addMethod("alpha", function(value, element) {
        return this.optional(element) || value.match(/^([a-z])+$/i);
    }, "Invalid alpha value");
    
    // alpha_numeric ( s4mple )
    jQuery.validator.addMethod("alpha_numeric", function(value, element) {
        return this.optional(element) || value.match(/^([a-z0-9])+$/i);
    }, "Invalid alpha-numeric characters");
    
    // alpha_dash ( sample-alpha_dash )
    jQuery.validator.addMethod("alpha_dash", function(value, element) {
        return this.optional(element) || value.match(/^([-a-z0-9_-])+$/i);
    }, "Invalid alpha-dash characters");

    // integer
    jQuery.validator.addMethod("integer", function(value, element) {
        return this.optional(element) || value.match(/^[\-+]?[0-9]+$/);
    }, "Invalid integer value");
     
    // decimal ( 6.11 )
    jQuery.validator.addMethod("decimal", function(value, element) {
        return this.optional(element) || value.match(/^[\-+]?[0-9]+\.[0-9]+$/);
    }, "Invalid decimal number");
    
    // is_natural positive numbers ( 1,2,3,4 etc )
    jQuery.validator.addMethod("is_natural", function(value, element) {
        return this.optional(element) || value.match(/^[0-9]+$/);
    }, "Invalid natural number");
   
    // is_natural_no_zero positive numbers ( 1,2,3,4 etc )
    jQuery.validator.addMethod("is_natural_no_zero", function(value, element) {
        return this.optional(element) || value.match(/^[0-9]+$/);
    }, "Invalid natural number");
    
    // valid_emails
    
    
    // valid_ip
    
    
    // valid_base64
    jQuery.validator.addMethod("valid_base64", function(value, element) {
        return this.optional(element) || value.match(/[^a-zA-Z0-9\/\+=]/);
    }, "Invalid base64 value");
    
    // valid_hex_color ( #ddd or #ffffff )
    jQuery.validator.addMethod("valid_hex_color", function(value, element) {
        return this.optional(element) || value.match(/^\#?[A-Fa-f0-9]{3}([A-Fa-f0-9]{3})?$/);
    }, "Invalid hex value. Please follow this format ( #ffffff )");
    
    // valid_rgb_color (  )
    jQuery.validator.addMethod("valid_rgb_color", function(value, element) {
        return this.optional(element) || value.match(/^rgb\(([01]?\d\d?|2[0-4]\d|25[0-5])\,([01]?\d\d?|2[0-4]\d|25[0-5])\,([01]?\d\d?|2[0-4]\d|25[0-5])\)$/);
    }, "Invalid rgb value. Please follow this format ( rgb(255,255,255) )");
    
    // valid_rgba_color (  )
    jQuery.validator.addMethod("valid_rgba_color", function(value, element) {
        return this.optional(element) || value.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
    }, "Invalid rgba value. Please follow this format ( rgba(255,255,255,0.25) )");
    
    // valid_hsl_color (  )
    jQuery.validator.addMethod("valid_hsl_color", function(value, element) {
        return this.optional(element) || value.match(/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g);
    }, "Invalid hsl value. Please follow this format ( hsl(255,255%,255%) )");
    
    // valid_hsla_color (  )
    jQuery.validator.addMethod("valid_hsla_color", function(value, element) {
        return this.optional(element) || true;
    }, "Invalid hsl value. Please follow this format ( hsla(255,255%,255%,0.25) )");

    // valid_12hr_time optional am/pm
    jQuery.validator.addMethod("valid_12hr_time", function(value, element) {
        // optional am/pm
//        return this.optional(element) || value.match(/^((([0]?[1-9]|1[0-2])(:|\.)[0-5][0-9]((:|\.)[0-5][0-9])?( )?(AM|am|aM|Am|PM|pm|pM|Pm))|(([0]?[0-9]|1[0-9]|2[0-3])(:|\.)[0-5][0-9]((:|\.)[0-5][0-9])?))$/);
        // no leading zero
//        return this.optional(element) || value.match(/^ *(1[0-2]|[1-9]):[0-5][0-9] *(a|p|A|P)(m|M) *$/);
        return this.optional(element) || value.match(/^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ [AaPp][Mm]))$/);
    }, "Invalid time format. Please follow this format ( hh:mm am )");

    // valid_12hr_sec_time without leading zero ( 9:45:59 am )
    jQuery.validator.addMethod("valid_12hr_sec_time", function(value, element) {
        // no leading zero
//        return this.optional(element) || value.match(/^ *(1[0-2]|[1-9]):[0-5][0-9]:[0-5][0-9] *(a|p|A|P)(m|M) *$/);
        return this.optional(element) || value.match(/^((0?[1-9]|1[012])(:[0-5]\d)(:[0-5]\d){1,2}(\ [AaPp][Mm]))$/);
    }, "Invalid time format. Please follow this format ( hh:mm:ss am )");

    // valid_24hr_time (  )
    jQuery.validator.addMethod("valid_24hr_time", function(value, element) {
        return this.optional(element) || value.match(/(^([0-9]|[0-1][0-9]|[2][0-3]):([0-5][0-9])$)|(^([0-9]|[1][0-9]|[2][0-3])$)/);
    }, "Invalid time format. Please follow this format ( hh:mm )");
    
    // valid_24hr_sec_time ( 1:59 )
    jQuery.validator.addMethod("valid_24hr_sec_time", function(value, element) {
        // with leading zero
//        return this.optional(element) || value.match(/(([0-1][0-9])|([2][0-3])):([0-5][0-9]):([0-5][0-9])/);
        return this.optional(element) || value.match(/(^([0-9]|[0-1][0-9])|([2][0-3])):([0-5][0-9]):([0-5][0-9]$)/);
    }, "Invalid time format. Please follow this format ( hh:mm:ss )");
    
    // valid_slash_date ( mm/dd/yyyy )
    jQuery.validator.addMethod("valid_slash_date", function(value, element) {
        return this.optional(element) || value.match(/^(([1-9])|(0[1-9])|(1[0-2]))\/(([0-9])|([0-2][0-9])|(3[0-1]))\/(([0-9][0-9])|([1-2][0,9][0-9][0-9]))$/);
    }, "Invalid date format. Please follow this format ( mm/dd/yyyy )");
    
    // valid_slash_datetime ( mm/dd/yyyy hh:mm am)
    jQuery.validator.addMethod("valid_slash_datetime", function(value, element) {
//        return this.optional(element) || value.match(/^([0]\d|[1][0-2])\/([0-2]\d|[3][0-1])\/([2][01]|[1][6-9])\d{2}(\s([0]\d|[1][0-2])(\:[0-5]\d){1,2})*\s*([aApP][mM]{0,2})?$/);
        return this.optional(element) || value.match(/^(([1-9])|(0[1-9])|(1[0-2]))\/(([0-9])|([0-2][0-9])|(3[0-1]))\/(([0-9][0-9])|([1-2][0,9][0-9][0-9]))\s((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ [AaPp][Mm]))$/);
    }, "Invalid date format. Please follow this format ( mm/dd/yyyy hh:mm am )");
    
    // valid_daterange ( mm/dd/yyyy - mm/dd/yyyy  )
    jQuery.validator.addMethod("valid_daterange", function(value, element) {
        return this.optional(element) || true;
    }, "Invalid date range format. Please follow this format ( mm/dd/yyyy - mm/dd/yyyy )");
    
    // valid_datetimerange ( mm/dd/yyyy hh:mm am - mm/dd/yyyy hh:mm am )
    jQuery.validator.addMethod("valid_datetimerange", function(value, element) {
        return this.optional(element) || true;
    }, "Invalid date range format. Please follow this format ( mm/dd/yyyy hh:mm am - mm/dd/yyyy hh:mm am )");
    
    jQuery.extend(jQuery.validator.messages, {
        required: "This field is required.",
        remote: "Please fix this field.",
        email: "Please enter a valid email address.",
        url: "Please enter a valid URL.",
        date: "Please enter a valid date.",
        dateISO: "Please enter a valid date (ISO).",
        number: "Please enter a valid number.",
        digits: "Please enter only digits.",
        creditcard: "Please enter a valid credit card number.",
        equalTo: "Please enter the same value again.",
        accept: "Please enter a value with a valid extension.",
        maxlength: jQuery.validator.format("Please enter no more than {0} characters."),
        minlength: jQuery.validator.format("Please enter at least {0} characters."),
        rangelength: jQuery.validator.format("Please enter a value between {0} and {1} characters long."),
        range: jQuery.validator.format("Please enter a value between {0} and {1}."),
        max: jQuery.validator.format("Please enter a value less than or equal to {0}."),
        min: jQuery.validator.format("Please enter a value greater than or equal to {0}."),
        // additional-methods
        extension: jQuery.validator.format("Please enter a value with valid file extension."),
        // custom fields
        greater_than: "Please enter value greater than {0}"
    });
});